---
sidebar_position: 2
---

# Static Tree Data Provider

When using an uncontrolled environment, you need to provide your data by supplying a data provider. The
easiest way to get started is using the [Static Tree Data Provider](/docs/api/classes/StaticTreeDataProvider).
It allows you to provide your data as record which maps item ids to tree items, and gives you the possibility
to react to changes in the tree structure, as well as inject your own changes through change events.

:::info
If you want to implement a custom data provider your own, you can find a comprehensive guide [here](/docs/guides/custom-data-provider).
:::

The following example gives a good example of what is possible with static tree data providers. We will look
into the details of the data provider below.

```jsx live
function App() {
  const items = useMemo(() => ({ ...shortTree.items }), []);
  const dataProvider = useMemo(
    () =>
      new StaticTreeDataProvider(items, (item, data) => ({
        ...item,
        data,
      })),
    [items]
  );

  const injectItem = () => {
    const rand = `${Math.random()}`;
    items[rand] = { data: 'New Item', index: rand };
    items.root.children.push(rand);
    dataProvider.onDidChangeTreeDataEmitter.emit(['root']);
  };

  const removeItem = () => {
    if (items.root.children.length === 0) return;
    items.root.children.pop();
    dataProvider.onDidChangeTreeDataEmitter.emit(['root']);
  };

  return (
    <UncontrolledTreeEnvironment
      canDragAndDrop
      canDropOnFolder
      canReorderItems
      dataProvider={dataProvider}
      getItemTitle={item => item.data}
      viewState={{
        'tree-1': {
          expandedItems: [],
        },
      }}
    >
      <button type="button" onClick={injectItem}>
        Inject item
      </button>
      <button type="button" onClick={removeItem}>
        Remove item
      </button>
      <Tree treeId="tree-1" rootItem="root" treeLabel="Tree Example" />
    </UncontrolledTreeEnvironment>
  );
}
```

## Creating the data provider with data

First, create the data provider. You want to make sure it isn't recreated on re-renders, so memoize
it in the component in which it is defined.

```tsx
const dataProvider = useMemo(
  () =>
    new StaticTreeDataProvider(items, (item, data) => ({
      ...item,
      data,
    })),
  [items]
);
```

The items is a record mapping item ids to tree items, for example:

```typescript
const items = [
  {
    index: "item-id",
    data: { arbitraryData: 123, name: "Hello" },
    children: ["item-id-1", "item-id-2"],
    isFolder: true
  }
]
```

Note that, whatever you provide to the `getItemTitle` prop is used to infer the item display name.

```ts jsx
<UncontrolledTreeEnvironment
  getItemTitle={item => item.data.name}
/>
```

## Apply changes from outside

You can apply changes to the underlying data source. Just make sure to let RCT know about that by
emitting a change event on the affected items. Note that, if you add or remove items, the affected item
is the parent item, not the added or removed items.

```ts
const injectItem = () => {
  const rand = `${Math.random()}`;
  items[rand] = { data: 'New Item', index: rand };
  items.root.children.push(rand);
  dataProvider.onDidChangeTreeDataEmitter.emit(['root']);
};

const removeItem = () => {
  if (items.root.children.length === 0) return;
  items.root.children.pop();
  dataProvider.onDidChangeTreeDataEmitter.emit(['root']);
};
```

## Reacting to Drag Events

Drag changes are always immediately applied to the visualization, so make sure to implement the `canDropAt`
prop to customize if that should not work in all cases. The static tree data emits tree change events similar
to the ones you would emit when applying changes from outside, so you can react to them in the same way.

```typescript
dataProvider.onDidChangeTreeData(changedItemIds => {
  console.log(changedItemIds);
});
```

## Reacting to Rename Events

The second (optional) parameter of the static tree data provider lets you react to rename events. Note that
you can customize whether renaming is possible in the first place through the `canRename` prop.

```typescript
const dataProvider = new StaticTreeDataProvider(items, (item, newName) => {
  // Return the patched item with new item name here
  return {
    ...item,
    data: { ...item.data, name: newName },
  };
});
`
```